﻿using System;
using System.Text;
using System.IO;
using System.Net;
using System.Web;
using System.Xml;

namespace TwitterXml
{

    /// <summary>
    /// A .NET wrapper library containing methods for the Twitter REST API. 
    /// Currently, all of the methods return an XMLDocument object. This may
    /// later be modified so that the methods return
    /// Status, DirectMessage, or User objects.
    /// </summary>
    public class Twitter
    {
        #region Private Fields

        // The maximum number of statuses that can be retreived.
        private const int maxCount = 200;

        // Results from the Twitter REST API will be returned in this data format.
        private const string format = ".xml";

        // The source parameter for Twitter XML.
        private const string sourceApp = "twitterxml";

        private const string createdAtDateFormat = "ddd MMM dd HH:mm:ss zzzz yyyy";
        private const string sinceDateFormat = "ddd MMM dd yyyy HH:mm:ss zzzz";

        private const string publicTimelineUrl = "http://twitter.com/statuses/public_timeline";
        private const string friendsTimelineUrl = "http://twitter.com/statuses/friends_timeline";
        private const string userTimelineUrl = "http://twitter.com/statuses/user_timeline";
        private const string statusShowUrl = "http://twitter.com/statuses/show";
        private const string statusUpdateUrl = "http://twitter.com/statuses/update";
        private const string statusRepliesUrl = "http://twitter.com/statuses/replies";
        private const string statusDestroyUrl = "http://twitter.com/statuses/destroy";

        private const string friendsUrl = "http://twitter.com/statuses/friends";
        private const string followersUrl = "http://twitter.com/statuses/followers";
        private const string featuredUrl = "http://twitter.com/statuses/featured";
        private const string userShowUrl = "http://twitter.com/users/show";

        private const string directMessagesUrl = "http://twitter.com/direct_messages";
        private const string directMessagesSentUrl = "http://twitter.com/direct_messages/sent";
        private const string directMessageNewUrl = "http://twitter.com/direct_messages/new";
        private const string directMessageDestroyUrl = "http://twitter.com/direct_messages/destroy";

        private const string friendshipCreateUrl = "http://twitter.com/friendships/create";
        private const string friendshipDestroyUrl = "http://twitter.com/friendships/destroy";

        private const string followUrl = "http://twitter.com/notifications/follow";
        private const string leaveUrl = "http://twitter.com/notifications/leave";


        // Twitter user name and password
        private string username;
        private string password;


        #endregion Private Fields


        #region Public Properties


        public static string CreatedAtDateFormat
        {
            get
            {
                return createdAtDateFormat;
            }
        }

        public static string SinceDateFormat
        {
            get
            {
                return sinceDateFormat;
            }
        }

        public static string Format
        {
            get
            {
                return format;
            }
        }


        public static string PublicTimelineUrl
        {
            get
            {
                return publicTimelineUrl;
            }
        }

        public static string FriendsTimelineUrl
        {
            get
            {
                return friendsTimelineUrl;
            }
        }

        public static string UserTimelineUrl
        {
            get
            {
                return userTimelineUrl;
            }
        }

        public static string StatusShowUrl
        {
            get
            {
                return statusShowUrl;
            }
        }

        public static string StatusUpdateUrl
        {
            get
            {
                return statusUpdateUrl;
            }
        }

        public static string StatusRepliesUrl
        {
            get
            {
                return statusRepliesUrl;
            }
        }

        public static string StatusDestroyUrl
        {
            get
            {
                return statusDestroyUrl;
            }
        }

        public static string FriendsUrl
        {
            get
            {
                return friendsUrl;
            }
        }

        public static string FollowersUrl
        {
            get
            {
                return followersUrl;
            }
        }

        public static string FeaturedUrl
        {
            get
            {
                return featuredUrl;
            }
        }

        public static string UserShowUrl
        {
            get
            {
                return userShowUrl;
            }
        }

        public static string DirectMessagesUrl
        {
            get
            {
                return directMessagesUrl;
            }
        }

        public static string DirectMessagesSentUrl
        {
            get
            {
                return directMessagesSentUrl;
            }
        }

        public static string DirectMessageNewUrl
        {
            get
            {
                return directMessageNewUrl;
            }
        }

        public static string DirectMessageDestroyUrl
        {
            get
            {
                return directMessageDestroyUrl;
            }
        }

        public static string FriendshipCreateUrl
        {
            get
            {
                return friendshipCreateUrl;
            }
        }

        public static string FriendshipDestroyUrl
        {
            get
            {
                return friendshipDestroyUrl;
            }
        }

        public static string FollowUrl
        {
            get
            {
                return followUrl;
            }
        }

        public static string LeaveUrl
        {
            get
            {
                return leaveUrl;
            }
        }


        public string UserName
        {
            get { return username; }
            set { username = value; }
        }

        public string Password
        {
            get { return password; }
            set { password = value; }
        }

        #endregion


        #region Constructors

        /// <summary>
        /// Constructor - without user authentication
        /// </summary>
        public Twitter()
        {
            this.username = "";
            this.password = "";
        }

        /// <summary>
        /// Constructor - with user authentication
        /// </summary>
        public Twitter(string username, string password)
        {
            this.username = username;
            this.password = password;
        }

        #endregion Constructors


        #region Public Methods

        #region Status Methods


        /// <summary>
        /// public_timeline -
        /// Returns the 20 most recent statuses from non-protected users who have set a custom user icon.
        /// </summary>
        /// <returns>
        /// XmlDocument containing 20 statuses.</returns>
        public XmlDocument GetPublicTimeline()
        {
            XmlDocument doc = new XmlDocument();
            string url = PublicTimelineUrl;
            url = url + Format;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// friends_timeline - 
        /// Returns the 20 most recent statuses posted by the authenticating user and that user's friends.
        /// </summary>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument GetFriendsTimeline()
        {
            return GetFriendsTimeline(DateTime.MinValue);
        }


        /// <summary>
        /// friends_timeline -
        /// Returns the 20 most recent statuses posted by the authenticating user and that user's friends
        /// since the given date.
        /// </summary>
        /// <param name="since">Narrows the returned results to just those statuses created after the specified date, up to 24 hours old</param>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument GetFriendsTimeline(DateTime since)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = FriendsTimelineUrl + Format;

            if (since != DateTime.MinValue)
                url = url + "?since=" + since.ToString(SinceDateFormat);

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// user_timeline - 
        /// Returns the 20 most recent statuses posted by the authenticating user.
        /// </summary>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument GetUserTimeline()
        {
            return GetUserTimeline(string.Empty, maxCount, DateTime.MinValue);
        }


        /// <summary>
        /// user_timeline - 
        /// Returns the 20 most recent statuses posted by the given user.
        /// </summary>
        /// <param name="userId">Specifies the ID or screen name of the user for whom to return the timeline.</param>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument GetUserTimeline(string userId)
        {
            return GetUserTimeline(userId, maxCount, DateTime.MinValue);
        }


        /// <summary>
        /// user_timeline - 
        /// Returns the requested number of most recent statuses posted by the authenticating user.
        /// </summary>
        /// <param name="count">Specifies the number of statuses to retreive. May not be greater than 200.</param>
        /// <returns>
        /// XmlDocument containing up to the requested number of statuses.</returns>
        public XmlDocument GetUserTimeline(int count)
        {
            return GetUserTimeline(string.Empty, count, DateTime.MinValue);
        }


        /// <summary>
        /// user_timeline - 
        /// Returns the 20 most recent statuses posted by the authenticating user
        /// since the given date.
        /// </summary>
        /// <param name="since">Narrows the returned results to just those statuses created after the specified date, up to 24 hours old</param>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument GetUserTimeline(DateTime since)
        {
            return GetUserTimeline(string.Empty, maxCount, since);
        }


        /// <summary>
        /// user_timeline - 
        /// Returns the requested number of most recent statuses posted by the authenticating user
        /// since the given date.
        /// </summary>
        /// <param name="count">Specifies the number of statuses to retreive. May not be greater than 200.</param>
        /// <param name="since">Narrows the returned results to just those statuses created after the specified date, up to 24 hours old</param>
        /// <returns>
        /// XmlDocument containing up to the requested number of statuses.</returns>
        public XmlDocument GetUserTimeline(int count, DateTime since)
        {
            return GetUserTimeline(string.Empty, count, since);
        }


        /// <summary>
        /// user_timeline - 
        /// Returns the 20 most recent statuses posted by the given user
        /// since the given date.
        /// </summary>
        /// <param name="userId">Specifies the ID or screen name of the user for whom to return the timeline.</param>
        /// <param name="since">Narrows the returned results to just those statuses created after the specified date, up to 24 hours old</param>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument GetUserTimeline(string userId, DateTime since)
        {
            return GetUserTimeline(userId, maxCount, since);
        }


        /// <summary>
        /// user_timeline - 
        /// Returns the requested number of most recent statuses posted by the given user
        /// since the given date.
        /// </summary>
        /// <param name="userId">Specifies the ID or screen name of the user for whom to return the timeline.</param>
        /// <param name="count">Specifies the number of statuses to retreive. May not be greater than 200.</param>
        /// <param name="since">Narrows the returned results to just those statuses created after the specified date, up to 24 hours old</param>
        /// <returns>
        /// XmlDocument containing up to the requested number of statuses.</returns>
        public XmlDocument GetUserTimeline(string userId, int count, DateTime since)
        {
            XmlDocument doc = new XmlDocument();
            string url;

            url = UserTimelineUrl;

            if (String.IsNullOrEmpty(userId))
                url = url + Format;
            else
                url = url + "/" + userId + Format;

            if (count > 0 && count < maxCount)
                url = url + "?count=" + count;

            if (since != DateTime.MinValue) 
            {
                url = url + "?since=" + since.ToString(SinceDateFormat);
            }

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// show - 
        /// Returns a single status, specified by the ID parameter.
        /// </summary>
        /// <param name="statusId">The numerical ID of the status you're trying to retreive.</param>
        /// <returns>
        /// XmlDocument containing a single status.</returns>
        public XmlDocument StatusShow(int statusId)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = StatusShowUrl + "/" + statusId + Format;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// update - Updates the authenticating user's status.
        /// </summary>
        /// <param name="status">The text of your status update. Should not be more than 140 characters</param>
        /// <returns>
        /// XmlDocument containing the new status.</returns>
        public XmlDocument StatusUpdate(string status)
        {
            if (String.IsNullOrEmpty(status))
                return null;

            XmlDocument doc = new XmlDocument();
            string url = StatusUpdateUrl;
            url = url + Format;
            string parameters = "&status=" + HttpUtility.UrlEncode(status);

            parameters += "&source=" + sourceApp;

            doc = HttpRequestResponseXml("POST", url, parameters);

            return doc;
        }


        /// <summary>
        /// replies - 
        /// Returns the 20 most recent @replies (status updates prefixed with @username) 
        /// for the authenticating user.
        /// </summary>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument StatusReplies()
        {
            return StatusReplies(-1);
        }


        /// <summary>
        /// replies - 
        /// Returns the 20 most recent @replies (status updates prefixed with @username) 
        /// for the authenticating user according to the given page number.
        /// </summary>
        /// <param name="page">Retreives the 20 next most recent replies.</param>
        /// <returns>
        /// XmlDocument containing up to 20 statuses.</returns>
        public XmlDocument StatusReplies(int page)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = StatusRepliesUrl + Format;

            if (page > 0)
            {
                url = url + "?page=" + page;
            }

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// destroy - Destroys the status specified by the required ID parameter
        /// </summary>
        /// <param name="statusId">The ID of the status to destroy.</param>
        /// <returns>
        /// XmlDocument containing the destroyed status.</returns>
        public XmlDocument StatusDestroy(int statusId)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = StatusDestroyUrl + "/" + statusId + Format;

            doc = HttpRequestResponseXml("POST", url);
            return doc;
        }

        #endregion Status Methods



        #region User Methods

        /// <summary>
        /// friends - 
        /// Returns up to 100 of the authenticating user's friends who have most recently updated, 
        /// each with current status inline.
        /// </summary>
        /// <returns>
        /// XmlDocument containing up to 100 users.</returns>
        public XmlDocument Friends()
        {
            string userId = UserName;
            int page = 1;
            return Friends(userId, page);
        }


        /// <summary>
        /// friends - 
        /// Returns up to 100 of the authenticating user's friends who have most recently updated, 
        /// each with current status inline according the to given page number.
        /// </summary>
        /// <param name="page">Retreives the next 100 friends</param>
        /// <returns>
        /// XmlDocument containing up to 100 users.</returns>
        public XmlDocument Friends(int page)
        {
            string userId = UserName;
            return Friends(userId, page);
        }


        /// <summary>
        /// friends - 
        /// Returns up to 100 of the specified user's friends who have most recently updated, 
        /// each with current status inline.
        /// </summary>
        /// <param name="userId">The ID or screen name of the user for whom to request a list of friends.</param> 
        /// <returns>
        /// XmlDocument containing up to 100 users.</returns>
        public XmlDocument Friends(string userId)
        {
            int page = 1;
            return Friends(userId, page);
        }


        /// <summary>
        /// friends - 
        /// Returns up to 100 of the specified user's friends who have most recently updated, 
        /// each with current status inline according the given page number.
        /// </summary>
        /// <param name="userId">The ID or screen name of the user for whom to request a list of friends.</param>
        /// <param name="page">Retreives the next 100 friends</param>
        /// <returns>
        /// XmlDocument containing up to 100 users.</returns>
        public XmlDocument Friends(string userId, int page)
        {
            XmlDocument doc = new XmlDocument();
            string url = FriendsUrl;

            if (String.IsNullOrEmpty(userId))
                url = url + Format;
            else
                url = url + "/" + userId + Format;

            if (page > 1)
                url = url + "?page=" + page;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }
        

        /// <summary>
        /// followers - 
        /// Returns the authenticating user's followers, each with current status inline.
        /// </summary>
        /// <returns>
        /// XmlDocument containing up to 100 users.</returns>
        public XmlDocument Followers()
        {
            string userId = UserName;
            int page = 1;
            return Followers(userId, page);
        }


       /// <summary>
       /// followers - 
       /// Returns the authenticating user's followers, each with current status inline
       /// according the given page number.
       /// </summary>
       /// <param name="page">Retrieves the next 100 followers.</param>
       /// <returns>
       /// XmlDocument containing up to 100 users.</returns>
       public XmlDocument Followers(int page)
        {
            string userId = UserName;
            return Followers(userId, page);
        }


        /// <summary>
        /// followers - 
        /// Returns the specified user's followers, each with current status inline.
        /// </summary>
        /// <param name="userId">The ID or screen name of the user for whom to request a list of followers.</param>
        /// <returns>
        /// XmlDocument containing up to 100 users.</returns>
        public XmlDocument Followers(string userId)
        {
            int page = 1;
            return Followers(userId, page);
        }


        /// <summary>
        /// followers - 
        /// Returns the specified user's followers, each with current status inline
        /// according the the given page number.
        /// </summary>
        /// <param name="userId">The ID or screen name of the user for whom to request a list of followers.</param>
        /// <param name="page">Retrieves the next 100 followers.</param>
        /// <returns>
        /// XmlDocument containing up to 100 users.</returns>
        public XmlDocument Followers(string userId, int page)
        {
            XmlDocument doc = new XmlDocument();
            string url = FollowersUrl;

            if (String.IsNullOrEmpty(userId))
                url = url + Format;
            else
                url = url + "/" + userId + Format;

            if (page > 1)
                url = url + "?page=" + page;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// show - 
        /// Returns the extended information of a given user.
        /// </summary>
        /// <param name="userId">The ID or screen name of a user.</param>
        /// <returns>
        /// XmlDocument containing a single user.</returns>
        public XmlDocument UserShow(string userId)
        {
            XmlDocument doc = new XmlDocument();
            string url = UserShowUrl + "/" + userId + Format;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// featured - Not listed on the API page. May no longer be supported.
        /// Returns Twitter's featured user's.
        /// </summary>
        /// <returns>
        /// XmlDocument containing users.</returns>
        public XmlDocument Featured()
        {
            XmlDocument doc = new XmlDocument();
            string url = FeaturedUrl + Format;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }

        #endregion User Methods


        #region Direct Message Methods

        /// <summary>
        /// direct_messages - 
        /// Returns a list of the 20 most recent direct messages sent to the authenticating user. 
        /// Includes detailed information about the sending and recipient users.
        /// </summary>
        /// <returns>
        /// XmlDocument containing up to 20 direct messages.</returns>
        public XmlDocument DirectMessages()
        {
            DateTime since = DateTime.MinValue;
            int page = 1;
            return DirectMessages(since, page);
        }


        /// <summary>
        /// direct_messages - 
        /// Returns a list of the 20 most recent direct messages sent to the authenticating user
        /// since the given ID and according the given page number. 
        /// Includes detailed information about the sending and recipient users.
        /// </summary>
        /// <param name="since_id">Returns only sent direct messages with an ID greater than (that is, more recent than) the specified ID.</param>
        /// <param name="page">Retrieves the 20 next most recent direct messages sent.</param>
        /// <returns>
        /// XmlDocument containing up to 20 direct messages.</returns>
        public XmlDocument DirectMessages(int since_id, int page)
        {
            XmlDocument doc = new XmlDocument();
            string url = DirectMessagesUrl;
            url = url + Format;

            if (since_id > 0)
                url = url + "?since_id=" + since_id;

            if (page > 1)
                url = url + "?page=" + page;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// direct_messages - 
        /// Returns a list of the 20 most recent direct messages sent to the authenticating user
        /// since the given date and according the given page number. 
        /// Includes detailed information about the sending and recipient users.
        /// </summary>
        /// <param name="since">Narrows the resulting list of direct messages to just those sent after the specified date, up to 24 hours old.</param>
        /// <param name="page">Retrieves the 20 next most recent direct messages sent.</param>
        /// <returns>
        /// XmlDocument containing up to 20 direct messages.</returns>
        public XmlDocument DirectMessages(DateTime since, int page)
        {
            XmlDocument doc = new XmlDocument();
            string url = DirectMessagesUrl;
            url = url + Format;

            if (since != DateTime.MinValue)
                url = url + "?since=" + since.ToString(SinceDateFormat);

            if (page > 1)
                url = url + "?page=" + page;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }

        
        /// <summary>
        /// sent - 
        /// Returns a list of the 20 most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <returns>
        /// XmlDocument containing up to 20 direct messages.</returns>
        public XmlDocument DirectMessagesSent()
        {
            DateTime since = DateTime.MinValue;
            int page = 1;
            return DirectMessagesSent(since, page);
        }


        /// <summary>
        /// sent - 
        /// Returns a list of the 20 most recent direct messages sent by the authenticating user
        /// since the given ID and according to the given page number.
        /// </summary>
        /// <param name="since_id">Returns only sent direct messages with an ID greater than (that is, more recent than) the specified ID.</param>
        /// <param name="page">Retrieves the 20 next most recent direct messages sent.</param>
        /// <returns>
        /// XmlDocument containing up to 20 direct messages.</returns>
        public XmlDocument DirectMessagesSent(int since_id, int page)
        {
            XmlDocument doc = new XmlDocument();
            string url = DirectMessagesSentUrl;
            url = url + Format;

            if (since_id > 0)
                url = url + "?since_id=" + since_id;

            if (page > 1)
                url = url + "?page=" + page;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }


        /// <summary>
        /// sent - 
        /// Returns a list of the 20 most recent direct messages sent by the authenticating user
        /// since the given date and according to the given page number.
        /// </summary>
        /// <param name="since">Narrows the resulting list of direct messages to just those sent after the specified date, up to 24 hours old.</param>
        /// <param name="page">Retrieves the 20 next most recent direct messages sent.</param>
        /// <returns>
        /// XmlDocument containing up to 20 direct messages.</returns>
        public XmlDocument DirectMessagesSent(DateTime since, int page)
        {
            XmlDocument doc = new XmlDocument();
            string url = DirectMessagesSentUrl;
            url = url + Format;

            if (since != DateTime.MinValue)
                url = url + "?since=" + since.ToString(SinceDateFormat);

            if (page > 1)
                url = url + "?page=" + page;

            doc = HttpRequestResponseXml("GET", url);
            return doc;
        }



        /// <summary>
        /// new - 
        /// Sends a new direct message to the specified user from the authenticating user. 
        /// Requires both the user and text parameters below.
        /// </summary>
        /// <param name="userId">The ID or screen name of the recipient user.</param>
        /// <param name="text">The text of your direct message.</param>
        /// <returns>
        /// XmlDocument containing the new direct message.</returns>
        public XmlDocument DirectMessageNew(string userId, string text)
        {
            if (String.IsNullOrEmpty(text))
                return null;

            XmlDocument doc = new XmlDocument();
            string url = DirectMessageNewUrl;
            url = url + Format;
            string parameters = "&user=" + HttpUtility.UrlEncode(userId) + "&text=" + HttpUtility.UrlEncode(text);

            doc = HttpRequestResponseXml("POST", url, parameters);

            return doc;
        }


        /// <summary>
        /// destroy - 
        /// Destroys the direct message specified in the required ID parameter. 
        /// The authenticating user must be the recipient of the specified direct message.
        /// </summary>
        /// <param name="msgId">The ID of the direct message to destroy.</param>
        /// <returns>XmlDocument containing the destroyed direct message.</returns>
        public XmlDocument DirectMessageDestroy(int msgId)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = DirectMessageDestroyUrl + "/" + msgId + Format;

            doc = HttpRequestResponseXml("POST", url);
            return doc;




        }

        #endregion Direct Message Methods


        #region Friendship Methods


        /// <summary>
        /// create - 
        /// Befriends the user specified in the ID parameter as the authenticating user.
        /// </summary>
        /// <param name="userId">The ID or screen name of the user to befriend.</param>
        /// <returns>
        /// XmlDocument containing the befriended user.</returns>
        public XmlDocument FriendshipCreate(string userId)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = FriendshipCreateUrl + "/" + userId + Format;

            doc = HttpRequestResponseXml("POST", url);
            return doc;
        }


        /// <summary>
        /// destroy - 
        /// Discontinues friendship with the user specified in the ID parameter as the 
        /// authenticating user.
        /// </summary>
        /// <param name="userId">The ID or screen name of the user with whom to discontinue friendship.</param>
        /// <returns>
        /// XmlDocument containing the un-friended user when successful. </returns>
        public XmlDocument FriendshipDestroy(string userId)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = FriendshipDestroyUrl + "/" + userId + Format;

            doc = HttpRequestResponseXml("POST", url);
            return doc;
        }

        #endregion Friendship Methods


        #region Notification Methods

        /// <summary>
        /// follow - 
        /// Enables notifications for updates from the specified user to the authenticating user. 
        /// </summary>
        /// <param name="userId">The ID or screen name of the user to follow.</param>
        /// <returns>
        /// XmlDocument containing the followed user when successful.</returns>
        public XmlDocument Follow(string userId)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = FollowUrl + "/" + userId + Format;

            doc = HttpRequestResponseXml("POST", url);
            return doc;
        }


        /// <summary>
        /// leave - 
        /// Disables notifications for updates from the specified user to the authenticating user.
        /// </summary>
        /// <param name="userId">The ID or screen name of the user to follow.</param>
        /// <returns>
        /// XmlDocument containing the left user when successful.</returns>
        public XmlDocument Leave(string userId)
        {
            XmlDocument doc = new XmlDocument();
            string url;
            url = LeaveUrl + "/" + userId + Format;

            doc = HttpRequestResponseXml("POST", url);
            return doc;
        }

        #endregion Notification Methods


        #endregion Public Methods


        #region Private Methods

        /// <summary>
        /// Create an HttpWebRequest using the given method ("POST" or "GET") and URL.
        /// </summary>
        /// <param name="method">"POST" or "GET". Other values default to "GET".</param>
        /// <param name="url">URL without any parameters</param>
        /// <returns></returns>
        private XmlDocument HttpRequestResponseXml(string method, string url)
        {
            return HttpRequestResponseXml(method, url, string.Empty);
        }

        /// <summary>
        /// Create an HttpWebRequest using the given method ("POST" or "GET"), URL, and parameters.
        /// </summary>
        /// <param name="method">"POST" or "GET". Other values default to "GET".</param>
        /// <param name="url">URL without any parameters</param>
        /// <param name="parameters">URL encoded paramaters in the form 
        /// "?paramName1=paramValue1?paramName2=paramValue2...</param>
        /// <returns></returns>
        private XmlDocument HttpRequestResponseXml(string method, string url, string parameters)
        {
            XmlDocument doc = new XmlDocument();
            // Create the web request
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            System.Net.ServicePointManager.Expect100Continue = false;

            request.PreAuthenticate = true;
            request.Credentials = new NetworkCredential(UserName, Password);
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = parameters.Length;

            if (method.Equals("POST"))
            {
                request.Method = method;
                // Write the request
                StreamWriter stOut = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
                
                if (!String.IsNullOrEmpty(parameters))
                    stOut.Write(parameters);

                stOut.Close();
            }
            // Else Assert: request.Method = "GET"

            try
            {
                // Get the Web Response  
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                    try
                    {
                        doc.Load(reader);
                    }
                    catch (XmlException xmlExcp)
                    {
                        //throw new XmlException(xmlExcp.Message);
                        doc.LoadXml("<XMLException>" + xmlExcp.Message + "</XMLException>");
                    }
                }
            }
            catch (WebException webExcp)
            {
                StreamReader reader = new StreamReader(webExcp.Response.GetResponseStream(), Encoding.UTF8);
                try
                {
                    doc.Load(reader);
                }
                catch (XmlException xmlExcp)
                {
                    //throw new XmlException(xmlExcp.Message);
                    doc.LoadXml("<Exception><WebException>" + webExcp.Message + "</WebException>" +
                        "<XMLException>" + xmlExcp.Message + "</XMLException></Exception>");
                }
                //throw new WebException(webExcp.Message);
                //doc.LoadXml("<BadResponse>" + webExcp.Message + "</BadResponse>");
            }
            return doc;
        }


        #endregion Private Methods

    }
}
